package com.atguigu.tingshu.user.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.util.MongoUtil;
import com.atguigu.tingshu.model.user.UserListenProcess;
import com.atguigu.tingshu.user.service.UserListenProcessService;
import com.atguigu.tingshu.vo.album.TrackStatMqVo;
import com.atguigu.tingshu.vo.user.UserListenProcessVo;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class UserListenProcessServiceImpl implements UserListenProcessService {

    private final MongoTemplate mongoTemplate;
    private final RedisTemplate<Object, Object> redisTemplate;
    private final RabbitService rabbitService;

    public UserListenProcessServiceImpl(MongoTemplate mongoTemplate, RedisTemplate<Object, Object> redisTemplate, RabbitService rabbitService) {
        this.mongoTemplate = mongoTemplate;
        this.redisTemplate = redisTemplate;
        this.rabbitService = rabbitService;
    }

    @Override
    public BigDecimal getTrackBreakSecondByTrackId(Long trackId, Long userId) {
        Query query = Query.query(Criteria.where("trackId").is(trackId).and("userId").is(userId)).limit(1);
        UserListenProcess userListenProcess = this.mongoTemplate.findOne(query, UserListenProcess.class,
                MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId));
        if (userListenProcess == null) {
            return BigDecimal.ZERO;
        }
        return userListenProcess.getBreakSecond();
    }

    @Override
    public void updateListenProcess(Long userId, UserListenProcessVo userListenProcessVo) {
        Long trackId = userListenProcessVo.getTrackId();
        Long albumId = userListenProcessVo.getAlbumId();
        // 构建查询条件
        Query query = Query.query(Criteria.where("trackId").is(trackId)
                        .and("userId").is(userId))
                .limit(1);

        // 查询用户播放进度信息
        UserListenProcess userListenProcess = this.mongoTemplate.findOne(query, UserListenProcess.class,
                MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId));
        // 如果用户播放进度信息不存在，则创建保存
        if (userListenProcess == null) {
            userListenProcess = new UserListenProcess();
            userListenProcess.setUserId(userId);
            userListenProcess.setAlbumId(albumId);
            userListenProcess.setTrackId(trackId);
            userListenProcess.setIsShow(1);
            userListenProcess.setCreateTime(new Date());
        }
        // 更新用户播放进度信息
        userListenProcess.setBreakSecond(userListenProcessVo.getBreakSecond());
        userListenProcess.setUpdateTime(new Date());
        this.mongoTemplate.save(userListenProcess, MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId));

        // 更新声音统计信息（track_stat）
        // 采用Redis的分布式锁 确保在规定时间内（24小时/当日内）播放进度统计更新1次
        String key = RedisConstant.USER_TRACK_REPEAT_STAT_PREFIX + userId + ":" + trackId;
        // 分布式锁持有时间为当天结束毫秒数减去当前毫秒数
        long expireTime = DateUtil.endOfDay(new Date()).getTime() - System.currentTimeMillis();
        Boolean block = this.redisTemplate.opsForValue().setIfAbsent(key, trackId, expireTime, TimeUnit.MILLISECONDS);
        if (Boolean.TRUE.equals(block)) {
            // 获取锁成功，则更新播放进度统计信息
            TrackStatMqVo trackStatMqVo = new TrackStatMqVo();
            trackStatMqVo.setBusinessNo(IdUtil.fastSimpleUUID());
            trackStatMqVo.setAlbumId(albumId);
            trackStatMqVo.setTrackId(trackId);
            trackStatMqVo.setStatType(SystemConstant.TRACK_STAT_PLAY);
            trackStatMqVo.setCount(1);
            // 向 RabbitMq 发送消息
            this.rabbitService.sendMessage(MqConst.EXCHANGE_TRACK, MqConst.ROUTING_TRACK_STAT_UPDATE, trackStatMqVo);

        }
    }

    @Override
    public Map<String, Long> getLatelyTrack(Long userId) {
        // 构建查询条件
        Query query = Query.query(Criteria.where("userId").is(userId))
                .with(Sort.by(Sort.Direction.DESC, "updateTime"))
                .limit(1);
        // 查询用户播放进度信息
        UserListenProcess userListenProcess = this.mongoTemplate.findOne(query, UserListenProcess.class,
                MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId));
        if (userListenProcess == null) {
            return Map.of();
        }
        return Map.of(
                "trackId", userListenProcess.getTrackId(),
                "albumId", userListenProcess.getAlbumId()
        );
    }
}
